/**
 * com_sys_tool.c
 * 系统通用工具函数源文件
 *
 */

#include "com_sys_tool.h" // 系统通用工具函数头文件



/**
 * @brief 多任务安全的绝对延时函数
 *
 * @param lastWakeTick  指向任务自己的上次唤醒 tick 计数（任务独立变量）
 * @param ms            延迟周期，单位毫秒
 *
 * 📘 原理详解：
 * --------------------------
 * CMSIS-RTOS 的时间单位是 “tick”，而不是毫秒。
 *
 * 例如：
 *  - 若 osKernelGetTickFreq() = 200，则每秒有200个tick；
 *    每个tick间隔 = 1000ms / 200 = 5ms。
 *
 * 普通的 osDelay(x) 是“相对延时”：
 *  - 从当前时刻延时x毫秒，不考虑任务执行时间；
 *  - 如果任务执行时间不同，周期会不稳定。
 *
 * 本函数是“绝对延时”：
 *  - 记录上次唤醒时间 lastWakeTick；
 *  - 每次延时都基于绝对时间计算下次唤醒点；
 *  - 即使任务执行时间略有变化，周期也稳定。
 *
 * --------------------------
 * 🧠 多任务安全的关键：
 * - 每个任务都维护自己独立的 lastWakeTick；
 * - 函数内部不使用全局变量；
 * - 多任务调用不会互相影响。
 */
void osDelay_absolute_safe(uint32_t *lastWakeTick, uint32_t ms)
{
    // 获取系统tick频率（每秒的tick数）
    uint32_t tickFreq = osKernelGetTickFreq();

    // 将毫秒转换为tick周期，例如 tickFreq=200 → 每tick=5ms
    uint32_t tickPeriod = 1000 / tickFreq; // 每个tick对应的毫秒数
    uint32_t delayTicks = ms / tickPeriod; // 需要延时的tick数

    // 第一次调用时初始化基准点（任务刚启动）
    if (*lastWakeTick == 0)
    {
        *lastWakeTick = osKernelGetTickCount();
    }

    // 计算下一次唤醒的绝对tick值
    uint32_t nextWakeTick = *lastWakeTick + delayTicks;

    // 获取当前系统tick
    uint32_t nowTick = osKernelGetTickCount();

    // 计算剩余的tick数（用int32_t防止溢出）
    int32_t remain = (int32_t)(nextWakeTick - nowTick);

    if (remain > 0)
    {
        // 说明当前时间还没到下次唤醒点 → 延时剩余时间
        osDelay(remain);
    }
    else
    {
        // 如果任务执行时间过长（超过设定周期）
        // 那么我们直接将基准点重置为当前时刻，避免累积误差
        nextWakeTick = nowTick;
    }

    // 更新基准tick，供下次调用使用
    *lastWakeTick = nextWakeTick;
}

void cm_mem_print_stats(void)
{
    cm_heap_stats_t stats;
    int32_t ret = cm_mem_get_heap_stats(&stats);

    if (ret != 0)
    {
        // 使用 cm_log_printf 打印错误信息，第一个参数为日志级别（0 保持与示例一致）
        cm_log_printf(0, "获取内存状态失败，错误码: %d\n", ret);
        return;
    }

    // 打印内存状态信息，使用日志级别 0（可根据实际需求调整）
    cm_log_printf(0, "====== 内存状态信息 ======\n");
    cm_log_printf(0, "总内存大小:       %u 字节\n", stats.total_size);
    cm_log_printf(0, "已分配内存:       %u 字节\n", stats.allocated);
    cm_log_printf(0, "空闲内存:         %u 字节\n", stats.free);

    // 计算并打印内存使用率
    if (stats.total_size > 0)
    {
        float usage = (float)stats.allocated * 100 / stats.total_size;
        cm_log_printf(0, "使用率:           %.2f%%\n", usage);
    }
    else
    {
        cm_log_printf(0, "使用率:           0.00%%\n");
    }
}